package aomo.mmma

import akka.Done
import akka.actor.typed.ActorRef
import akka.actor.typed.ActorSystem
import akka.actor.typed.Behavior
import akka.cluster.sharding.typed.scaladsl._
import akka.persistence.journal.Tagged
import akka.persistence.typed.PersistenceId
import akka.persistence.typed.scaladsl.Effect
import akka.persistence.typed.scaladsl.EventSourcedBehavior
import akka.persistence.typed.scaladsl.ReplyEffect
import akka.persistence.typed.scaladsl.RetentionCriteria
import akka.actor.typed.scaladsl.Behaviors
import aomo.mmma.Persona.{Command, Event, Hibernate, TaskDone}

import scala.collection.mutable

/**
 *
 * @author liuzhenchuan@foxmail.com
 * @date 2021/3/26
 */
object Persona{

  trait Event
  case class SmsSendResult(val task: String, success:Boolean, data:String, cur:Int) extends Event
  case class AttributeFetchResult(val task: String, code:String, success:Boolean, data:String, cur:Int) extends Event
  case class EventArrived(val task: String, code:String, success:Boolean, data:String, cur:Int) extends Event
  case class Timeout(val task: String, data:String, cur:Int) extends Event
  case class TaskDone(val task: String, cur:Int) extends Event


  trait Command
  case class SendSms(account:String,data:String) extends Command
  case class FetchAttribute(account:String,data:String) extends Command
  case class RegistEvent(event:String) extends Command
  case class RegistDelay(event:String) extends Command
  case object Hibernate extends Command
  case class RegistTask(task:String,start: Boolean=false)
  case class StartTask(task: String)
  case class PauseTask(task:String)
  case class FinishTask(task:String)


  def apply(profile:String,id:String): EventSourcedBehavior[Command, Event, State] = new Profile(profile, id)
}

object Task{

}

case class TaskStateMachine(state: Map[(Int,Event),Int],nodes:Map[Int,ActorRef[Command]]){
  def nextState(curStep:Int,event:Event):Int={
    state.getOrElse((curStep, event), -1)
  }
}

case class TaskState(map: Map[String,String])

final case class State(taskState: scala.collection.mutable.Map[String,String]=mutable.HashMap.empty){

  def applyEvent(event: Event):State={
    event match {
      case done:TaskDone=>
        taskState.get(done.task)
        return this
    }
  }

  def applyCommand(command: Command):Effect[Event, State]={
    command match {
      case Hibernate=>
        Effect.none
    }
  }

}

class Persona(profile:String,id: String) {

  def behavior(profile:String,id: String): EventSourcedBehavior[Command, Event, State] = {

    EventSourcedBehavior[Command, Event, State](
      persistenceId = PersistenceId(s"uid_${profile}", id),
      emptyState = State(),
      // command handler: (State, Command) => Effect
      commandHandler = (account, cmd) => account.applyCommand(cmd),
      // event handler: (State, Event) => State
      eventHandler = (account, evt) => account.applyEvent(evt)
    ).withRetention(RetentionCriteria.snapshotEvery(numberOfEvents = 10, keepNSnapshots = 2))
      .snapshotWhen {      // save a snapshot when a predicate holds
        case (state, evt: TaskDone, seqNr) => true
        case _                           => false
      }
  }


}
